/*
 * Copyright (c) 2012 Andrea De Rinaldis <ozioso at ipignoli.dyndns.org>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.dyndns.ipignoli.droidcruise;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import org.dyndns.ipignoli.droidcruise.controller.DeviceIdentifier;
import org.dyndns.ipignoli.droidcruise.controller.LocationPostNew;
import org.dyndns.ipignoli.droidcruise.controller.MyAsyncTask.EndTaskListener;
import org.dyndns.ipignoli.droidcruise.controller.RouteLoader;
import org.dyndns.ipignoli.droidcruise.controller.RoutePostNew;
import org.dyndns.ipignoli.droidcruise.db.MyHelper;
import org.dyndns.ipignoli.droidcruise.http.LocationPoster;
import org.dyndns.ipignoli.droidcruise.http.RoutePoster;
import org.dyndns.ipignoli.droidcruise.notifications.MyNotification;
import org.dyndns.ipignoli.droidcruise.notifications.MyNotificationManager;
import org.dyndns.ipignoli.droidcruise.position.CurrentPosition;
import org.dyndns.ipignoli.droidcruise.position.MyLocationListener;
import org.dyndns.ipignoli.droidcruise.recording.Recording;
import org.dyndns.ipignoli.droidcruise.routes.RouteList;
import org.dyndns.ipignoli.droidcruise.themes.DarkTheme;
import org.dyndns.ipignoli.droidcruise.timer.UIUpdater;
import org.dyndns.ipignoli.droidcruise.ui.DisclaimerDialog;
import org.dyndns.ipignoli.droidcruise.ui.GpsUI;
import org.dyndns.ipignoli.droidcruise.ui.RadarUI;
import org.dyndns.ipignoli.droidcruise.ui.RouteUI;
import org.dyndns.ipignoli.droidcruise.ui.SpeedUI;
import org.dyndns.ipignoli.droidcruise.ui.TipDialog;
import org.dyndns.ipignoli.droidcruise.util.CommonStore;
import org.dyndns.ipignoli.droidcruise.util.MyContext;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


public class DroidCruise extends Activity implements
    OnSharedPreferenceChangeListener, TextToSpeech.OnInitListener{
  public static final int            DEBUG_LEVEL                   = Log.DEBUG;
  public static final int            GPS_NOTIFICATION_MIN_TIME     = 1000;

  private static final int           GPS_NOTIFICATION_MIN_DISTANCE = 0;
  private static final int           GPS_MIN_ACCURACY              = 30;
  private static final int           GPS_NOTIFICATION              = 1;
  private static final int           ROUTE_NOTIFICATION            = 2;
  private static final int           RADAR_NOTIFICATION            = 3;
  private static final int           SPEED_NOTIFICATION            = 4;
  private static final int           INTENT_CHECK_TTS              = 0;
  private static final Locale        DEFAULT_LOCALE                =
                                                                       Locale.ENGLISH;
  private static final String        LANGUAGES_AVAILABLE           =
                                                                       "::en::it::";
  private static final int           DOUBLE_BACK_TIME              = 2000;
  // private static final int DIGIT_HEIGHT_RATIO = 6;
  // private static final int LARGE_DIGIT_HEIGHT_RATIO = 10;

  private static Map<String, String> DEFAULT_PREFERENCES;
  static{
    DEFAULT_PREFERENCES = new HashMap<String, String>();
    DEFAULT_PREFERENCES.put("always_notify", "true");
    DEFAULT_PREFERENCES.put("orientation",
        String.valueOf(ActivityInfo.SCREEN_ORIENTATION_USER));
    DEFAULT_PREFERENCES.put("speed_limit", "0");
    DEFAULT_PREFERENCES.put("gps_accuracy", String.valueOf(GPS_MIN_ACCURACY));
    DEFAULT_PREFERENCES.put("use_tts", "true");
    DEFAULT_PREFERENCES.put("send_recordings", "false");
    DEFAULT_PREFERENCES.put("show_tips", "true");
    DEFAULT_PREFERENCES.put("show_disclaimer", "true");
  }

  private boolean                    ended;

  private Intent                     notificationIntent;

  private RouteUI                    routeUI;
  private RadarUI                    radarUI;
  private GpsUI                      gpsUI;
  private SpeedUI                    speedUI;
  private ImageView[]                imgSpeed                      =
                                                                       new ImageView[3];
  private ImageView[]                imgAverageSpeed               =
                                                                       new ImageView[3];
  private ImageView[]                imgSuggestedSpeed             =
                                                                       new ImageView[3];
  private ImageButton                btnVolume;
  private ImageButton                btnRecordRoute;
  private ImageButton                btnTutor;
  private ImageButton                btnRadar;

  private boolean                    gpsDisabledShowing;
  private DisclaimerDialog           disclaimerDialog;
  private boolean                    disclaimerShowing;
  private TipDialog                  tipDialog;
  private boolean                    tipsShowing;
  private String[]                   tips;

  private SharedPreferences          preferences;
  private SharedPreferences.Editor   preferenceEditor;

  private boolean                    routesLoading;
  private RouteList                  routes;
  private CurrentPosition            currentPosition;

  private TextToSpeech               tts;
  private boolean                    ttsLaunched;

  private MyHelper                   dbHelper;

  private String                     deviceID;
  private RoutePoster                routePoster;
  private LocationPoster             tutorPoster;
  private LocationPoster             radarPoster;

  private long                       lastBackPress;
  private Toast                      tstBackPress;

  @Override
  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    Log.println(DEBUG_LEVEL, "droidcruise.DroidCruise.onCreate",
        "stateTrack DroidCruise.onCreate");

    MyContext.initialize(this);

    ended = false;

    notificationIntent = new Intent(this, DroidCruise.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    setContentView(R.layout.main);
    imgSpeed[0] = (ImageView)findViewById(R.id.img_speed_u);
    imgSpeed[1] = (ImageView)findViewById(R.id.img_speed_t);
    imgSpeed[2] = (ImageView)findViewById(R.id.img_speed_h);
    imgAverageSpeed[0] = (ImageView)findViewById(R.id.img_avgspeed_u);
    imgAverageSpeed[1] = (ImageView)findViewById(R.id.img_avgspeed_t);
    imgAverageSpeed[2] = (ImageView)findViewById(R.id.img_avgspeed_h);
    imgSuggestedSpeed[0] = (ImageView)findViewById(R.id.img_sgtspeed_u);
    imgSuggestedSpeed[1] = (ImageView)findViewById(R.id.img_sgtspeed_t);
    imgSuggestedSpeed[2] = (ImageView)findViewById(R.id.img_sgtspeed_h);

    // DisplayMetrics dm = new DisplayMetrics();
    // getWindowManager().getDefaultDisplay().getMetrics(dm);
    //
    // int imgHeight=dm.heightPixels/DIGIT_HEIGHT_RATIO;
    // int imgWidth=imgHeight*2/3;
    // for(int i=0;i<imgSpeed.length;i++){
    // imgSpeed[i].setMinimumHeight(imgHeight);
    // imgSpeed[i].setMinimumWidth(imgWidth);
    // }
    // for(int i=0;i<imgAverageSpeed.length;i++){
    // imgAverageSpeed[i].setMinimumHeight(imgHeight);
    // imgAverageSpeed[i].setMinimumWidth(imgWidth);
    // }
    //
    // int largeImgHeight=dm.heightPixels/LARGE_DIGIT_HEIGHT_RATIO;
    // int largeImgWidth=largeImgHeight*2/3;
    // for(int i=0;i<imgSuggestedSpeed.length;i++){
    // imgSuggestedSpeed[i].setMinimumHeight(largeImgHeight);
    // imgSuggestedSpeed[i].setMinimumWidth(largeImgWidth);
    // }

    btnVolume = (ImageButton)findViewById(R.id.btn_volume);
    btnVolume.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        MyNotificationManager.getInstance().setMuteOrUnmute();
        if(MyNotificationManager.getInstance().isMute()){
          btnVolume.setImageResource(R.drawable.btn_volume_on);
          Toast.makeText(DroidCruise.this, R.string.volume_off,
              Toast.LENGTH_LONG).show();
        }
        else{
          btnVolume.setImageResource(R.drawable.btn_volume_off);
          Toast.makeText(DroidCruise.this, R.string.volume_on,
              Toast.LENGTH_LONG).show();
        }
      }
    });

    btnRecordRoute = (ImageButton)findViewById(R.id.btn_record_route);
    btnRecordRoute.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        UIUpdater updater = UIUpdater.getInstance();
        if(updater.isRecordingRoute()){
          if(routePoster == null){
            Toast.makeText(DroidCruise.this, R.string.Device_not_ready,
                Toast.LENGTH_LONG).show();
            return;
          }
          btnRecordRoute.setImageResource(R.drawable.btn_record_route_start);
          final boolean send =
              preferences.getBoolean("send_recordings", Boolean
                  .parseBoolean(DEFAULT_PREFERENCES.get("send_recordings")));
          new RoutePostNew(DroidCruise.this, new EndTaskListener<Boolean>(){
            @Override
            public void notify(final Boolean result){
              if(result != null && result)
                if(send)
                  Toast.makeText(DroidCruise.this,
                      R.string.Information_sent_Thanks, Toast.LENGTH_LONG)
                      .show();
                else
                  Toast.makeText(DroidCruise.this,
                      R.string.Information_recorded, Toast.LENGTH_LONG).show();
            }
          }, routePoster, send).execute(updater.stopRouteRecording());
        }
        else{
          if(updater.startRouteRecording()){
            Toast.makeText(DroidCruise.this, R.string.Route_recording_started,
                Toast.LENGTH_LONG).show();
            btnRecordRoute.setImageResource(R.drawable.btn_record_route_stop);
          }
          else
            Toast.makeText(DroidCruise.this, R.string.Device_not_ready,
                Toast.LENGTH_LONG).show();
        }
      }
    });

    btnTutor = (ImageButton)findViewById(R.id.btn_tutor);
    btnTutor.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        if(tutorPoster == null || currentPosition == null
            || currentPosition.getLastPosition() == null){
          Toast.makeText(DroidCruise.this, R.string.Device_not_ready,
              Toast.LENGTH_LONG).show();
          return;
        }
        final boolean send =
            preferences.getBoolean("send_recordings", Boolean
                .parseBoolean(DEFAULT_PREFERENCES.get("send_recordings")));
        new LocationPostNew(DroidCruise.this, new EndTaskListener<Boolean>(){
          @Override
          public void notify(Boolean result){
            if(result != null && result)
              if(send)
                Toast.makeText(DroidCruise.this,
                    R.string.Information_sent_Thanks, Toast.LENGTH_LONG).show();
              else
                Toast.makeText(DroidCruise.this, R.string.Information_recorded,
                    Toast.LENGTH_LONG).show();
          }
        }, tutorPoster, send).execute(currentPosition.getLastPosition());
      }
    });

    btnRadar = (ImageButton)findViewById(R.id.btn_radar);
    btnRadar.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        if(radarPoster == null || currentPosition == null
            || currentPosition.getLastPosition() == null){
          Toast.makeText(DroidCruise.this, R.string.Device_not_ready,
              Toast.LENGTH_LONG).show();
          return;
        }
        final boolean send =
            preferences.getBoolean("send_recordings", Boolean
                .parseBoolean(DEFAULT_PREFERENCES.get("send_recordings")));
        new LocationPostNew(DroidCruise.this, new EndTaskListener<Boolean>(){
          @Override
          public void notify(Boolean result){
            if(result != null && result)
              if(send)
                Toast.makeText(DroidCruise.this,
                    R.string.Information_sent_Thanks, Toast.LENGTH_LONG).show();
              else
                Toast.makeText(DroidCruise.this, R.string.Information_recorded,
                    Toast.LENGTH_LONG).show();
          }
        }, radarPoster, send).execute(currentPosition.getLastPosition());
      }
    });

    tips = getResources().getStringArray(R.array.tips);

    tts = null;
    ttsLaunched = false;

    dbHelper = new MyHelper(this);

    deviceID = null;
    routePoster = null;
    tutorPoster = null;
    radarPoster = null;

    lastBackPress = 0;
    tstBackPress = null;

    routeUI =
        new RouteUI((TextView)findViewById(R.id.txt_limit),
            (TextView)findViewById(R.id.txt_end),
            (TextView)findViewById(R.id.txt_route), getResources().getString(
                R.string.Tutor_free_route), new MyNotification(
                ROUTE_NOTIFICATION, R.drawable.stat_notify_tutor,
                getResources().getString(R.string.Tutor_alert), getResources()
                    .getString(R.string.Road_monitored_by_tutor), "",
                notificationIntent));

    radarUI =
        new RadarUI(new MyNotification(RADAR_NOTIFICATION,
            R.drawable.stat_notify_radar, getResources().getString(
                R.string.Radar_alert), getResources().getString(
                R.string.Speed_control_approaching), getResources().getString(
                R.string.Watch_your_speed), notificationIntent));

    gpsUI =
        new GpsUI((ImageView)findViewById(R.id.img_gps_state),
            R.drawable.gps_ok, R.drawable.gps_warning, R.drawable.gps_alert,
            new MyNotification(GPS_NOTIFICATION,
                R.drawable.stat_notify_gps_warning, getResources().getString(
                    R.string.GPS_alert), getResources().getString(
                    R.string.Inaccurate_GPS_position), getResources()
                    .getString(R.string.Possible_bad_satellite_reception),
                notificationIntent), new MyNotification(GPS_NOTIFICATION,
                R.drawable.stat_notify_gps_alert, getResources().getString(
                    R.string.GPS_alert), getResources().getString(
                    R.string.GPS_unavailable), getResources().getString(
                    R.string.GPS_is_disabled_or_bad_satellite_reception),
                notificationIntent));

    speedUI =
        new SpeedUI(imgSpeed, imgAverageSpeed, imgSuggestedSpeed, 0,
            new DarkTheme(), new MyNotification(SPEED_NOTIFICATION,
                R.drawable.stat_notify_speed, getResources().getString(
                    R.string.Speed_alert), getResources().getString(
                    R.string.Speed_limit_overlayed), getResources().getString(
                    R.string.Please_slow_down), notificationIntent));

    gpsDisabledShowing = false;
    disclaimerShowing = false;
    tipsShowing = false;
    routesLoading = false;
  }

  @Override
  public void onPause(){
    super.onPause();
    Log.println(DEBUG_LEVEL, "droidcruise.DroidCruise.onPause",
        "stateTrack DroidCruise.onPause");

    if(!ended)
      saveState();

    // cleanViews(findViewById(R.id.root_layout));
    // System.gc();
  }

  @Override
  public void onResume(){
    super.onResume();
    Log.println(DEBUG_LEVEL, "droidcruise.DroidCruise.onResume",
        "stateTrack DroidCruise.onResume");
    restoreState();
  }

  @Override
  public void finish(){
    ended = true;
    stopThreads();
    clearState();
    MyNotificationManager.getInstance().clearAll();
    if(tstBackPress != null)
      tstBackPress.cancel();
    super.finish();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu){
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.droidcruise_menu, menu);
    return true;
  }

  @Override
  public boolean onMenuItemSelected(int featureId, MenuItem item){
    switch(item.getItemId()){
      case R.id.droidcruise_preferences:
        Intent helpIntent = new Intent(this, Preferences.class);
        startActivity(helpIntent);
        return true;

      case R.id.droidcruise_recording_list:
        Intent intent = new Intent(this, RecordingList.class);
        startActivity(intent);
        return true;
    }

    return super.onMenuItemSelected(featureId, item);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data){
    Log.println(DEBUG_LEVEL, "droidcruise.DroidCruise.onActivityResult",
        "stateTrack DroidCruise.onActivityResult");
    if(requestCode == INTENT_CHECK_TTS){
      if(resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS){
        tts = new TextToSpeech(this, this);
        setTTS();
      }
      return;
    }
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event){
    if(keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0){
      manageCancel();
      return true;
    }

    return super.onKeyDown(keyCode, event);
  }

  // private void cleanViews(View view){
  // if(view.getBackground() != null){
  // view.getBackground().setCallback(null);
  // }
  // if(view instanceof ViewGroup){
  // for(int i = 0; i < ((ViewGroup)view).getChildCount(); i++){
  // cleanViews(((ViewGroup)view).getChildAt(i));
  // }
  // try{
  // ((ViewGroup)view).removeAllViews();
  // }catch(UnsupportedOperationException e){}
  // }
  // }

  private void manageCancel(){
    if(getLastBackPress() + DOUBLE_BACK_TIME > System.currentTimeMillis())
      finish();
    else{
      tstBackPress =
          Toast.makeText(this, R.string.Press_back_again_to_exit,
              Toast.LENGTH_LONG);
      tstBackPress.show();
      setLastBackPress();
    }
  }

  private synchronized long getLastBackPress(){
    return lastBackPress;
  }

  private synchronized void setLastBackPress(){
    lastBackPress = System.currentTimeMillis();
  }

  private void saveState(){
    if(deviceID != null)
      CommonStore.getInstance().put(CommonStore.DROID_CRUISE_DEVICE_ID,
          deviceID);

    if(preferences != null)
      CommonStore.getInstance().put(CommonStore.DROID_CRUISE_PREFERENCES,
          preferences);

    if(routes != null)
      CommonStore.getInstance().put(CommonStore.DROID_CRUISE_ROUTES, routes);

    if(currentPosition != null)
      CommonStore.getInstance().put(CommonStore.DROID_CRUISE_CURRENT_POSITION,
          currentPosition);

    if(tipDialog != null)
      CommonStore.getInstance().put(CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED,
          new Boolean(tipDialog.showAgain()));
    else if(CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED))
      CommonStore.getInstance().remove(
          CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED);

    if(disclaimerDialog != null)
      CommonStore.getInstance().put(
          CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED,
          new Boolean(disclaimerDialog.showAgain()));
    else if(CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED))
      CommonStore.getInstance().remove(
          CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED);

    CommonStore.getInstance().put(CommonStore.DROID_CRUISE_RESUME, null);

    if(!preferences.getBoolean("always_notify",
        Boolean.parseBoolean(DEFAULT_PREFERENCES.get("always_notify"))))
      stopThreads();
  }

  private void launchTtsActivity(){
    Log.println(DroidCruise.DEBUG_LEVEL,
        "droidcruise.DroidCruise.launchTtsActivity", "launching tts activity");

    Intent checkIntent = new Intent();
    try{
      checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
      startActivityForResult(checkIntent, INTENT_CHECK_TTS);
    }catch(ActivityNotFoundException e){}
    ttsLaunched = true;
  }

  private void restoreState(){
    if(!ttsLaunched) // Don't move this down! Must stay on top of the method.
      launchTtsActivity();

    if(CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_PREFERENCES)){
      preferences =
          (SharedPreferences)CommonStore.getInstance().get(
              CommonStore.DROID_CRUISE_PREFERENCES);
    }
    else{
      preferences = PreferenceManager.getDefaultSharedPreferences(this);
      preferences.registerOnSharedPreferenceChangeListener(this);
    }
    preferenceEditor = preferences.edit();

    if(CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_CURRENT_POSITION))
      currentPosition =
          (CurrentPosition)CommonStore.getInstance().get(
              CommonStore.DROID_CRUISE_CURRENT_POSITION);
    else
      currentPosition = new CurrentPosition();

    if(CommonStore.getInstance()
        .containsKey(CommonStore.DROID_CRUISE_DEVICE_ID)){
      deviceID =
          (String)CommonStore.getInstance().get(
              CommonStore.DROID_CRUISE_DEVICE_ID);
      routePoster = new RoutePoster(deviceID);
      tutorPoster = new LocationPoster(deviceID, Recording.TUTOR_TYPE);
      radarPoster = new LocationPoster(deviceID, Recording.RADAR_TYPE);
    }
    else
      new DeviceIdentifier(this,
          new DeviceIdentifier.EndTaskListener<String>(){
            @Override
            public void notify(String result){
              if(result == null)
                return;
              deviceID = result;
              routePoster = new RoutePoster(deviceID);
              tutorPoster = new LocationPoster(deviceID, Recording.TUTOR_TYPE);
              radarPoster = new LocationPoster(deviceID, Recording.RADAR_TYPE);
            }
          }).execute((Object[])null);

    if(CommonStore.getInstance().containsKey(CommonStore.DROID_CRUISE_ROUTES)){
      routes =
          (RouteList)CommonStore.getInstance().get(
              CommonStore.DROID_CRUISE_ROUTES);
      routeUI.setText(routes.getSelectedRoute());
      MyLocationListener.getInstance().setRoutes(routes);
    }
    else if(!routesLoading){
      routesLoading = true;
      new RouteLoader(this, new RouteLoader.EndTaskListener<RouteList>(){
        @Override
        public void notify(RouteList result){
          if(result == null)
            return;
          routes = result;
          routeUI.setText(routes.getSelectedRoute());
          MyLocationListener.getInstance().setRoutes(routes);
          Toast.makeText(DroidCruise.this,
              R.string.Route_data_loading_complete, Toast.LENGTH_LONG).show();
          Log.println(DEBUG_LEVEL, "droidcruise.DroidCruise.restoreState",
              "Route data loading complete");
        }
      }).execute(getResources().openRawResource(R.raw.routes));
    }

    if(!CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_TIPS_SHOWN)
        && !tipsShowing)
      if(preferences.getBoolean("show_tips",
          Boolean.parseBoolean(DEFAULT_PREFERENCES.get("show_tips"))))
        showTips((new Random()).nextInt(tips.length));
      else
        CommonStore.getInstance()
            .put(CommonStore.DROID_CRUISE_TIPS_SHOWN, null);

    if(!CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_DISCLAIMER_SHOWN)
        && !disclaimerShowing)
      if(preferences.getBoolean("show_disclaimer",
          Boolean.parseBoolean(DEFAULT_PREFERENCES.get("show_disclaimer")))){
        disclaimerShowing = true;
        disclaimerDialog = new DisclaimerDialog(this);
        if(CommonStore.getInstance().containsKey(
            CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED))
          disclaimerDialog.setShowAgain((Boolean)CommonStore.getInstance().get(
              CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED));
        disclaimerDialog.getButton().setOnClickListener(new OnClickListener(){
          @Override
          public void onClick(View v){
            preferenceEditor.putBoolean("show_disclaimer",
                disclaimerDialog.showAgain());
            preferenceEditor.commit();
            CommonStore.getInstance().put(
                CommonStore.DROID_CRUISE_DISCLAIMER_SHOWN, null);
            disclaimerDialog.cancel();
          }
        });
        disclaimerDialog.show();
      }
      else
        CommonStore.getInstance().put(
            CommonStore.DROID_CRUISE_DISCLAIMER_SHOWN, null);

    MyLocationListener.getInstance(routes, routeUI, radarUI, gpsUI,
        currentPosition, Integer.parseInt(preferences.getString("gps_accuracy",
            DEFAULT_PREFERENCES.get("gps_accuracy"))));

    LocationManager locationManager =
        (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    if(!CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_GPS_DISABLED_SHOWN)
        && !gpsDisabledShowing)
      if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
        gpsDisabledShowing = true;
        (new AlertDialog.Builder(this))
            .setIcon(android.R.drawable.ic_dialog_info)
            .setTitle(R.string.GPS_unavailable)
            .setMessage(R.string.GPS_is_disabled_do_you_wish_to_activate_it)
            .setCancelable(false)
            .setPositiveButton(R.string.ok,
                new DialogInterface.OnClickListener(){
                  @Override
                  public void onClick(DialogInterface dialog, int which){
                    Intent intent =
                        new Intent(
                            android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(intent);
                  }
                }).setNegativeButton(R.string.Cancel, null).show();
      }
      else
        CommonStore.getInstance().put(
            CommonStore.DROID_CRUISE_GPS_DISABLED_SHOWN, null);

    locationManager.addGpsStatusListener(MyLocationListener.getInstance());
    MyLocationListener.getInstance().start();
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
        GPS_NOTIFICATION_MIN_TIME, GPS_NOTIFICATION_MIN_DISTANCE,
        MyLocationListener.getInstance());

    for(String k: preferences.getAll().keySet())
      onSharedPreferenceChanged(preferences, k);

    if(MyNotificationManager.getInstance().isMute())
      btnVolume.setImageResource(R.drawable.btn_volume_on);
    else
      btnVolume.setImageResource(R.drawable.btn_volume_off);

    UIUpdater updater =
        UIUpdater
            .getInstance(speedUI, currentPosition, gpsUI, routeUI, radarUI);
    updater.restart();
    if(updater.isRecordingRoute())
      btnRecordRoute.setImageResource(R.drawable.btn_record_route_stop);
    else
      btnRecordRoute.setImageResource(R.drawable.btn_record_route_start);
  }

  private void clearState(){
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_DEVICE_ID);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_PREFERENCES);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_ROUTES);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_CURRENT_POSITION);
    CommonStore.getInstance().remove(
        CommonStore.DROID_CRUISE_GPS_DISABLED_SHOWN);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_TIPS_SHOWN);
    CommonStore.getInstance()
        .remove(CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_DISCLAIMER_SHOWN);
    CommonStore.getInstance().remove(
        CommonStore.DROID_CRUISE_SHOW_DISCLAIMER_CHECKED);
    CommonStore.getInstance().remove(CommonStore.DROID_CRUISE_RESUME);
    if(tts != null)
      tts.shutdown();
  }

  private void stopThreads(){
    if(MyLocationListener.getInstance() != null){
      MyLocationListener.getInstance().stop();
      LocationManager locationManager =
          (LocationManager)getSystemService(Context.LOCATION_SERVICE);
      locationManager.removeUpdates(MyLocationListener.getInstance());
      locationManager.removeGpsStatusListener(MyLocationListener.getInstance());
    }

    if(UIUpdater.getInstance() != null)
      UIUpdater.getInstance().stop();
  }

  private void setTTS(){
    if(preferences == null){
      launchTtsActivity();
      return;
    }

    Log.println(DroidCruise.DEBUG_LEVEL, "droidcruise.DroidCruise.setTTS",
        "setting tts=" + tts);

    MyNotificationManager.getInstance().setTts(
        preferences.getBoolean("use_tts",
            Boolean.parseBoolean(DEFAULT_PREFERENCES.get("use_tts"))) ? tts
            : null);
  }

  private void showTips(final int index){
    tipsShowing = true;
    tipDialog =
        new TipDialog(this, getResources().getString(R.string.Tip) + " # "
            + (index + 1), tips[index]);

    if(CommonStore.getInstance().containsKey(
        CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED))
      tipDialog.setShowAgain((Boolean)CommonStore.getInstance().get(
          CommonStore.DROID_CRUISE_SHOW_TIPS_CHECKED));

    tipDialog.getButtonOK().setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        preferenceEditor.putBoolean("show_tips", tipDialog.showAgain());
        preferenceEditor.commit();
        CommonStore.getInstance()
            .put(CommonStore.DROID_CRUISE_TIPS_SHOWN, null);
        tipDialog.cancel();
      }
    });

    tipDialog.getButtonPrevious().setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        tipDialog.cancel();
        showTips((index + tips.length - 1) % tips.length);
      }
    });

    tipDialog.getButtonNext().setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v){
        tipDialog.cancel();
        showTips((index + 1) % tips.length);
      }
    });
    tipDialog.show();
  }

  @Override
  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
      String key){
    if(key.equals("orientation")){
      setRequestedOrientation(Integer.parseInt(preferences.getString(key,
          String.valueOf(DEFAULT_PREFERENCES.get(key)))));
      return;
    }
    if(key.equals("speed_limit")){
      speedUI.setSpeedLimitPC(Integer.parseInt(preferences.getString(key,
          DEFAULT_PREFERENCES.get(key))));
      return;
    }
    if(key.equals("gps_accuracy")){
      MyLocationListener.getInstance().setMinAccuracy(
          Integer.parseInt(preferences.getString(key,
              DEFAULT_PREFERENCES.get(key))));
      return;
    }
    if(key.equals("use_tts")){
      setTTS();
      return;
    }
  }

  @Override
  public void onInit(int status){
    if(status != TextToSpeech.SUCCESS){
      tts = null;
      return;
    }

    if(!LANGUAGES_AVAILABLE.contains("::"
        + Locale.getDefault().getLanguage().toString() + "::"))
      tts.setLanguage(DEFAULT_LOCALE);
  }
}
